package com.dylan.channel.v10.channel;

import com.dylan.channel.v10.NioEventLoop;
import com.dylan.channel.v10.future.ChannelPromise;

import java.net.SocketAddress;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;

public abstract class AbstractNioChannel extends AbstractChannel {

    private final SelectableChannel ch;
    volatile SelectionKey selectionKey;

    //channel要关注的事件
    protected final int readInterestOp;

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
    }

    protected SelectableChannel javaChannel() {
        return this.ch;
    }

    @Override
    public NioUnsafe unsafe() {
        return (NioUnsafe) super.unsafe();
    }
    @Override
    public NioEventLoop eventLoop() {
        return (NioEventLoop) super.eventLoop();
    }


    protected abstract boolean doConnect(SocketAddress remoteAddress) throws Exception;


    @Override
    public void doBeginRead() {
        final SelectionKey selectionKey = this.selectionKey;
        //检查key是否是有效的
        if (!selectionKey.isValid()) {
            return;
        }

        //还没有设置感兴趣的事件，所以得到的值为0
        final int interestOps = selectionKey.interestOps();

        //interestOps中并不包含readInterestOp
        if ((interestOps & readInterestOp) == 0) {
            //设置channel关注的事件，读事件
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }



    public interface NioUnsafe extends Unsafe {

        SelectableChannel ch();

        void finishConnect();

        void read();

        void forceFlush();
    }

    protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe{
        @Override
        public final SelectableChannel ch() {
            return javaChannel();
        }
        /**
         * @Author: PP-jessica
         * @Description:该方法回到了原本的位置
         */
        @Override
        public void connect(SocketAddress remoteAddress, final SocketAddress localAddress, ChannelPromise promise) {
            try {
                boolean doConnect = doConnect(remoteAddress);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void finishConnect() {

        }

        @Override
        public void read() {

        }

        @Override
        public void forceFlush() {

        }
    }

    protected void doRegister() {
        //在这里把channel注册到单线程执行器中的selector上,注意这里的第三个参数this，这意味着channel注册的时候把本身，也就是nio类的channel
        //当作附件放到key上了，之后会用到这个。
        try {
            SelectableChannel channel = javaChannel();
            selectionKey = channel.register(eventLoop().getSelect(), 0, this);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
